home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d18 / tpschk11.arc / SELFCHK.PAS < prev   
Pascal/Delphi Source File  |  1991-04-28  |  9KB  |  213 lines

  1. Unit SelfChk;
  2.  
  3. {$I-}
  4.  
  5. (*                                                                     *)
  6. (*  The SelfChk Unit, Release 1.1, 02/05/1990.                         *)
  7. (*                                                                     *)
  8. (*  This UNIT for Borland's Turbo Pascal version 4.0+ provides your    *)
  9. (*  programs with a means of checking themselves for changes at run-   *)
  10. (*  time as both an anti-viral and anti-hack measure.                  *)
  11. (*                                                                     *)
  12. (*  This UNIT is (C) 1990 by Michael S. Durkin and is distributed as   *)
  13. (*  SHAREWARE.  Registration information is within the documentation,  *)
  14. (*  and is requested if you use The SelfChk Unit in your programs.     *)
  15. (*  You may NOT distribute modified source code.  Do NOT modify this   *)
  16. (*  or any other copyright notice.                                     *)
  17. (*                                                                     *)
  18. (*  Please forward any examples/suggestions for improvement or bug     *)
  19. (*  reports to me for consideration or fixes.                          *)
  20. (*                                                                     *)
  21. (*    Mike Durkin          The TeleSoft RBBS-PC                        *)
  22. (*    P.O. Box 1021        Data: (415) 969-8238                        *)
  23. (*    Mt. View, CA          Four Lines (CAPAL)                         *)
  24. (*        94042-1021       FidoNet: (1:143/204)                        *)
  25. (*                                                                     *)
  26. (*  Place SelfChk in your Uses statement.  Execute SCHKINST against    *)
  27. (*  your executable after compilation.  Within your program use the    *)
  28. (*  DoSelfChk procedure to generate the CRC.  SelfChkResult is bit     *)
  29. (*  mapped as noted below with the result of the SelfChk.  Or, call    *)
  30. (*  ChkIntegrity (as an example) to check your executable and it'll    *)
  31. (*  take appropriate action.  The low order Word of the FileSize of    *)
  32. (*  your program is used as an initial seed value for the 16 bit CRC   *)
  33. (*  routine (rather than $0000) for additional security.               *)
  34. (*                                                                     *)
  35. (*  The SelfChk Unit will add, typically from 0.8 to 1.8k to your      *)
  36. (*  programs filesize depending on how many of the standard procedures *)
  37. (*  this unit uses, that your program already used.  Memory usage      *)
  38. (*  depends in part on the size of the disk buffer you choose.  I      *)
  39. (*  recommend sharing the disk buffer with your main program to cut    *)
  40. (*  down on memory usage.                                              *)
  41. (*                                                                     *)
  42. (*  And a final note:  A condition of your use of The SelfChk Unit is  *)
  43. (*  that you don't make fun of my programming!  It may be awful, but   *)
  44. (*  it gets the job done, and with a minimum of resources and time.    *)
  45. (*  If there is any part of this unit that confuses you, I'll be glad  *)
  46. (*  to clear it up.                                                    *)
  47. (*                                                                     *)
  48.  
  49. INTERFACE
  50.  
  51. Uses Dos;
  52.  
  53. Const
  54.   SelfChkResult : Byte = 0;   { Bit Mapped result after call to DoSelfChk (bit) }
  55.                               {  0 := SelfChk appears fine                  -   }
  56.                               {  1 := IOError - couldn't check              0   }
  57.                               {  2 := 16bit CRC (w/filesize seed) failed    1   }
  58.  
  59. (* Note:  The following 4 constants must remain at minimum in this order  *)
  60. (*  to ensure that SCHKINST can find them during data installation and    *)
  61. (*  change 'file_crc' to reflect the actual CRC (seed=lo_word(filesize)). *)
  62.  
  63.   data_ofs    : LongInt = $FFFFFFFF;  { OffSet to DATA installed by SCHKINST }
  64.   file_crc    : Word    = $FFFF    ;  { crc of exec    installed by SCHKINST }
  65.   crc_ccitt   : Word    = $0000    ;  { runtime generation vs. file_crc      }
  66.   schk_sign   : LongInt = $4B484353;  { verification for SCHKINST. Ensures that  }
  67.                                       { SCHKINST is looking at the right data    }
  68.  
  69. Var  { Share these with your main program, if you like, just don't }
  70.      { call a procedure from this unit if you need the value of    }
  71.      { these variables to stay the same.                           }
  72.   disk_buf               : Array[1..2048] of Byte;  { disk buffer, ok to change size }
  73.   table_ccitt            : Array [0..255] of Word;
  74.   f                      : File;
  75.   counter, result,
  76.   counter2               : Integer;
  77.   bytesCRCed             : LongInt;
  78.   exec_fname             : String;    { initiliazed to the executables drive/path/filename }
  79.  
  80. Procedure DoSelfChk;     { Compute seeded CRC and set SelfChkResult.          }
  81.  
  82. Procedure ChkIntegrity;  { Calls DoSelfChk, examines SelfChkResult, and acts  }
  83.                          { accordingly.  Use this or write your own.          }
  84.  
  85. Procedure UpdSelfChkData; 
  86.                          { Computes CRC and installs the value into itself.   }
  87.                          { If your program updates itself, then call this     }
  88.                          { procedure after you do your update to update the   }
  89.                          { SelfChk CRC data.  Note: Minimal error checking    }
  90.                          { is done.  Please see the Documentation for special }
  91.                          { considerations if you use this procedure.  It is   }
  92.                          { also expected that you modify bytes and/or append  }
  93.                          { to the file only, so 'data_ofs' should not change. }
  94.  
  95. Procedure Crc_gen( Var s; length : Integer); 
  96.                          { Generally NOT called by the user. It's placed here }
  97.                          { for use by SCHKINST.  If you do wish to generate   }
  98.                          { the CRC of a buffer, set crc_ccitt := 0, and result}
  99.                          { to the length of the buffer.  Then call this       }
  100.                          { procedure as crc_gen(buf_name, length_buf);  The   }
  101.                          { CRC of the buffer is placed in crc_ccitt.  For a   }
  102.                          { file, read the next block, and leave crc_ccitt set }
  103.                          { at the CRC of the previous block.                  }
  104.  
  105. IMPLEMENTATION
  106.  
  107. {$I crc_gen.inc}
  108.  
  109. Procedure DoSelfChk;
  110.  
  111. Begin    { Self Check code. }
  112.  
  113. {$I-}
  114.   FileMode := 0;                                   { ReadOnly Mode }
  115.   Assign(f,exec_fname);
  116.   Reset(f,1);
  117.   If IOResult <> 0 Then Begin
  118.        SelfChkResult := SelfChkResult OR $01;
  119.        Exit;
  120.      End;
  121.  
  122. (* Compute the 16 bit CRC using the low order word of *)
  123. (* the programs FileSize as an initial seed value.    *)
  124.  
  125.   crc_ccitt := FileSize(f);
  126.   bytesCRCed := 0;
  127.   REPEAT
  128.     BlockRead(f,disk_buf,SizeOf(disk_buf),result);
  129.  
  130.     (* The next IF..THEN restores the 6 bytes which were altered by SCHKINST *)
  131.     (* during data installation to the value ($FF) SCHKINST saw them as      *)
  132.     (* when it computed the CRC.  This is necessary, and does NOT sacrifice  *)
  133.     (* the integrity of the self check.  Any byte(s)/bit(s) changed will     *)
  134.     (* still generate a bad self check result.                               *)
  135.  
  136.     If ((data_ofs OR (data_ofs+5)) >= bytesCRCed) AND ((data_ofs OR (data_ofs+5)) <= (bytesCRCed+result)) Then
  137.              For counter := 1 to result Do
  138.                   If ((data_ofs+1) <= (bytesCRCed + counter)) AND
  139.                      ((bytesCRCed + counter) <= (data_ofs+6)) Then disk_buf[counter] := $FF;
  140.  
  141.     crc_gen(disk_buf,result);
  142.     bytesCRCed := bytesCRCed + result;
  143.   UNTIL Eof(f);
  144.   Close(f);
  145.  
  146.  
  147. (* Compare the runtime CRC computation with the CRC installed by SCHKINST *)
  148. (* If the two don't match, set the result bit for a bad self check.       *)
  149.  
  150.   If (crc_ccitt <> file_crc) Then SelfChkResult := SelfChkResult OR $04;
  151.  
  152.   FileMode := 2;                                      { Read/Write Mode }
  153.  
  154. End; { Procedure }
  155.  
  156. Procedure ChkIntegrity;
  157.  
  158. Begin
  159.  
  160.   DoSelfChk;
  161.   If (SelfChkResult AND $01) = $01 Then WriteLn('  Note:  I/O Error during CRC SelfChk!');
  162.   If SelfChkResult > 1 Then Begin
  163.       WriteLn(#7,'WARNING:  ',exec_fname,' fails CRC SelfChk!',#7);
  164.      Halt;
  165.    End;
  166.  
  167. End; { Procedure ChkIntegrity }
  168.  
  169. Procedure UpdSelfChkData;
  170.  
  171. Var
  172.   fattr : Word;
  173.  
  174. Begin
  175.  
  176.   DoSelfChk;
  177.   Assign(f,exec_fname);
  178.   GetFAttr(f,fattr);
  179.   SetFAttr(f,$00);
  180.   Reset(f,1);
  181.   Seek(f,data_ofs+4);
  182.   BlockWrite(f,crc_ccitt,2);
  183.   SetFAttr(f,fattr);  
  184.   Close(f);
  185.  
  186. End; { Procedure UpdSelfChkData }
  187.  
  188. {$I+}
  189.  
  190. Begin { Unit Init Code }
  191.  
  192.   exec_fname := ParamStr(0);
  193.  
  194. (* build the crc table at runtime  -  saves approx.    *)
  195. (* 400 bytes in the .EXE w/ minimal runtime overhead.  *)
  196. (* Modified from the Public Domain program - FILETEST  *)
  197.  
  198. For counter := 0 to 255 Do
  199.   Begin
  200.      result := counter;
  201.      For counter2 := 1 to 8 Do
  202.         Begin
  203.            If (result and 1) = 1
  204.               then result := (result shr 1) xor $8404 { $8404 = CCITT polynomial }
  205.               else result :=  result shr 1;
  206.         End;
  207.  
  208.      table_ccitt[counter] := result;
  209.   End
  210.  
  211. End. { of Unit }
  212.  
  213.